package net.qiqbframework.loadhanding;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.Registration;
import net.qiqbframework.common.utils.CollectionUtil;
import net.qiqbframework.messaging.annotation.*;
import net.qiqbframework.modelling.domain.AggregateModel;
import net.qiqbframework.modelling.domain.AggregateModelFactory;
import net.qiqbframework.modelling.domain.BizIdentifierModel;

import java.util.*;

/**
 * 加载
 *
 * @param <T>
 */
@Slf4j
public class AnnotationLoadHandlerAdapter<T> implements LoadMessageHandler {


    private final T target;

    private final AnnotatedHandlerInspector<T> handlerInspector;

    private final AggregateModelFactory aggregateModelFactory;

    public AnnotationLoadHandlerAdapter(T annotatedLoader, HandlerParameterResolverFactory parameterResolverFactory,
                                        HandlerAttributesPostProcessor handlerAttributesPostProcessor,
                                        MessageHandlingMemberFactory handlerDefinition,
                                        AggregateModelFactory aggregateModelFactory) {
        this.target = annotatedLoader;
        this.aggregateModelFactory = aggregateModelFactory;
        this.handlerInspector = AnnotatedHandlerInspector.inspectType((Class<T>) annotatedLoader.getClass(), parameterResolverFactory, handlerAttributesPostProcessor, handlerDefinition);

    }


    public Registration subscribe(AggregateLoadBus loadBus) {
        final List<LoadExecutableHandler> loadExecutableHandlerList = handlerInspector.getAllHandlers().values().stream().toList()
                .stream()
                .flatMap(Collection::stream)
                .map(ch -> ch.unwrap(LoadExecutableHandler.class).orElse(null))
                .filter(Objects::nonNull).toList();
        List<Registration> registrations = new ArrayList<>();
        for (LoadExecutableHandler loadExecutableHandler : loadExecutableHandlerList) {
            final Optional<String> bizIdentifierNameOptional = loadExecutableHandler.bizIdentifierName();
            if (bizIdentifierNameOptional.isEmpty()) {
                // 尝试从类型获取
                final Class<?> bizIdentifierType = loadExecutableHandler.bizIdentifierType();
                final Optional<AggregateModel<Object>> aggregateModel = aggregateModelFactory.getModel(loadExecutableHandler.aggregateName());
                if (aggregateModel.isPresent()) {
                    final List<BizIdentifierModel<?>> matchedBizModel = aggregateModel.get().allBizIdentifierModels().stream().filter(bm -> bm.bizIdentifierType() == bizIdentifierType).toList();
                    if (matchedBizModel.isEmpty()) {
                        throw new IllegalArgumentException("[%s]加载器无法确认业务ID[%s]名称".formatted(aggregateModel.get().modelName(),bizIdentifierType));

                    }
                    if (matchedBizModel.size() > 1) {
                        throw new IllegalArgumentException("[%s]加载器无法确认多个业务ID[%s]名称".formatted(aggregateModel.get().modelName(),bizIdentifierType));
                    }
                    loadExecutableHandler.updateBizIdentifierName(matchedBizModel.get(0).modelName());
                }
            }

            registrations.add(loadBus.subscribe(loadExecutableHandler.aggregateName(), loadExecutableHandler.bizIdentifierName().orElseThrow(), this));

        }


        return () -> registrations.stream().map(Registration::cancel).reduce(Boolean::logicalOr).orElse(false);
    }


    @Override
    public Object handle(LoadMessage<?> loadMessage) throws Exception {

        final List<MessageExecutableHandler> matchedMessageHandlingMember = handlerInspector.getHandlers(target.getClass())
                .filter(ch -> ch.canHandle(loadMessage))
                .toList();
        if (CollectionUtil.isEmpty(matchedMessageHandlingMember)) {
            return null;
        }
        if (matchedMessageHandlingMember.size() > 1) {
            throw new IllegalArgumentException("找到多个加载器");
        }
        final MessageExecutableHandler messageExecutableHandler = matchedMessageHandlingMember.get(0);
        return handlerInspector.chainedInterceptor(target.getClass()).handle(loadMessage, target, messageExecutableHandler);
    }


}
